﻿using System;
using System.Threading;
using AccelerateSensor.Model.Gateway;
using AccelerateSensor.Model.Node;
using AccelerateSensor.SocketServer.Tools;
using SuperSocket.SocketBase;
using AccelerateSensor.SocketServer.Handler;

namespace AccelerateSensor.SocketServer.Server
{
    public class MySession : AppSession<MySession, MyRequestInfo>, ISensorDataObserver
    {
        public new MyServer AppServer => (MyServer) base.AppServer;
        public string Id => $"{RemoteEndPoint.Address}.{RemoteEndPoint.Port}";
        public bool Timeout => (DateTime.Now - UpdateTime).TotalSeconds > 30;

        #region UpdateTime

        private DateTime _updateTime;
        private static readonly object UpdateTimeLockHelper = new object();

        private DateTime UpdateTime
        {
            get
            {
                lock (UpdateTimeLockHelper)
                {
                    return _updateTime;
                }
            }
            set
            {
                lock (UpdateTimeLockHelper)
                {
                    _updateTime = value;
                }
            }
        }

        #endregion

        private readonly SensorDataHandler _sensorDataHandler;
        private long _packageNumber;

        public MySession()
        {
            _sensorDataHandler = new SensorDataHandler(this);
        }

        protected override void OnSessionStarted()
        {
            //Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] - " +
            //                  $"New Session Connected: {RemoteEndPoint.Address} " +
            //                  $"@ {RemoteEndPoint.Port}.");
            AppServer.RegisterSession(this);
            _sensorDataHandler.Start();
            UpdateTime = DateTime.Now;
            LogHelper.AddLog($"New Session Connected: {RemoteEndPoint.Address}.{RemoteEndPoint.Port}");
        }

        protected override void HandleUnknownRequest(MyRequestInfo requestInfo)
        {
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] - "
                              + $"Unknown request {requestInfo.Key}.");
            //Send("Unknown request.");
            LogHelper.AddLog($"Unknown request {requestInfo.HexString}.");
        }

        protected override void HandleException(Exception e)
        {
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] - "
                              + $"Application error: {e.Message}.");
            //Send($"Application error: {e.Message}.");
            LogHelper.AddLog($"Application error: {e.Message}.");
        }

        protected override void OnSessionClosed(CloseReason reason)
        {
            //Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] - " +
            //                  $"Session {RemoteEndPoint.Address} @ {RemoteEndPoint.Port} " +
            //                  $"Closed: {reason}.");
            LogHelper.AddLog($"Session {RemoteEndPoint.Address}.{RemoteEndPoint.Port} Closed: {reason}.");
            AppServer.UnRegisterSession(Id);
            _sensorDataHandler.Stop();
            base.OnSessionClosed(reason);
        }

        public void ReceiveSensorData(string data)
        {
            UpdateTime = DateTime.Now;
            AddPackageCount();
            //LogHelper.AddLog($"Receive sensor data: {data}");
            //Console.WriteLine($"Receive sensor data: {data}");
            _sensorDataHandler.AddMessage(data);
        }

        #region 统计数据

        private void AddPackageCount()
        {
            Interlocked.Increment(ref _packageNumber);
        }

        public void ResetPackageCount()
        {
            Interlocked.Exchange(ref _packageNumber, 0);
        }

        public long PackageCount => Interlocked.Read(ref _packageNumber);

        #endregion

        #region ISensorDataObserver

        public void ReceiveHeartbeat()
        {
            UpdateTime = DateTime.Now;

            var heartbeatLenBuffer = MessageHelper.GetHeartbeatLenBuffer();
            Send(heartbeatLenBuffer, 0, heartbeatLenBuffer.Length);

            var heartbeatBuffer = MessageHelper.GetHeartbeatBuffer();
            Send(heartbeatBuffer, 0, heartbeatBuffer.Length);

            LogHelper.AddLog("Send heartbeat back to client.");
            Console.WriteLine("Send heartbeat back to client.");
        }

        public void ReceiveGatewayInfo(GatewayInfo info)
        {
            SocketServerManager.Instance.ReceiveGatewayInfo(info);
        }

        public void ReceiveNodeInfo(NodeInfo info)
        {
            SocketServerManager.Instance.ReceiveNodeInfo(info);
        }

        public void ReceiveNodeData(NodeData data)
        {
            SocketServerManager.Instance.ReceiveNodeData(data);
        }

        #endregion
    }
}
